package org.keco.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;

import org.keco.shape.AbstractShape;
import org.keco.shape.Line;
import org.keco.shape.Point;
import org.keco.shape.Rectangle;
import org.keco.shape.complex.ShapeChain;

public class PlotingArea extends JPanel {

	private static final long serialVersionUID = -3438557201960896592L;

	private static final int SNAP_DISTANCE = 10;

	private PlotingArea THIS;

	private ShapeChain chain = new ShapeChain();

	private JToggleButton btnLine = new JToggleButton(new ImageIcon("line.png"), false);
	private JToggleButton btnArc = new JToggleButton(new ImageIcon("arc.png"), false);
	private JToggleButton btnSelect = new JToggleButton(new ImageIcon("select.png"), false);

	private JCheckBox snap = new JCheckBox("snap", false);

	private JTextArea textConsole = new JTextArea();

	private Point pressed;

	public PlotingArea() {
		THIS = this;

		this.setBackground(Color.LIGHT_GRAY);
		this.setLayout(new BorderLayout());

		JPanel btnPanel = new JPanel();
		btnPanel.add(snap);
		btnPanel.add(btnSelect);
		btnPanel.add(btnLine);
		btnPanel.add(btnArc);

		ButtonGroup group = new ButtonGroup();
		group.add(btnArc);
		group.add(btnLine);
		group.add(btnSelect);

		textConsole.setRows(5);
		this.add(btnPanel, BorderLayout.NORTH);
		this.add(new JScrollPane(textConsole), BorderLayout.SOUTH);

		this.addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseMoved(MouseEvent e) {
			}

			@Override
			public void mouseDragged(MouseEvent e) {
				if (btnLine.isSelected()) {
					Point eventPoint = getPoint(e);
					if (!pressed.isSame(eventPoint)) {
						Line line = new Line(pressed, eventPoint);
						chain.setTmpShape(line);
						THIS.repaint();
					}
				} else if (btnSelect.isSelected()) {
					chain.setSelectionShape(new Rectangle(pressed, getPoint(e)));
					THIS.repaint();
				}
			}
		});

		this.addMouseListener(new MouseListener() {

			@Override
			public void mouseReleased(MouseEvent e) {
				chain.setSelectionShape(null);
				if (btnLine.isSelected()) {
					Point eventPoint = getPoint(e);
					if (!pressed.isSame(eventPoint)) {
						Line line = new Line(pressed, eventPoint);
						chain.addShape(line);

					}
				}
				THIS.repaint();
			}

			@Override
			public void mousePressed(MouseEvent e) {
				if (snap.isSelected()) {
					pressed = findNearestPoint(getPoint(e));
				} else {
					pressed = getPoint(e);
				}
			}

			@Override
			public void mouseExited(MouseEvent e) {
			}

			@Override
			public void mouseEntered(MouseEvent e) {
			}

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					chain.deselectAllShapes();
					Point p = getPoint(e);
					for (AbstractShape c : chain.getShapes()) {
						if (c.containsPoint(p)) {
							c.selectShape();
							break;
						}
					}
				}
				// chain.fromString(textConsole.getText());
				THIS.repaint();
			}
		});

		this.addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub

			}
		});
	}

	public int convertY(int y) {
		return this.getHeight() - y;
	}

	public Point getPoint(MouseEvent e) {
		return new Point(e.getX(), e.getY());
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		chain.paint(g);
		textConsole.setText(chain.toString());
	}

	public Point findNearestPoint(Point p) {
		if (chain.getShapes().isEmpty()) {
			return p;
		} else {
			Point returnPoint = null;
			for (Component c : chain.getShapes()) {
				if (c instanceof Line) {
					int dist = p.calculateDistance(((Line) c).getStart());
					if (dist < SNAP_DISTANCE) {
						returnPoint = ((Line) c).getStart();
					}
					dist = p.calculateDistance(((Line) c).getEnd());
					if (dist < SNAP_DISTANCE) {
						returnPoint = ((Line) c).getEnd();
					}
				}
			}
			return returnPoint == null ? p : returnPoint;
		}
	}

}
